package com.service.bracelet.service.impl;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.service.bracelet.common.CommonResult;
import com.service.bracelet.common.CommonResultPage;
import com.service.bracelet.dao.LumenMapper;
import com.service.bracelet.entity.Lumen;
import com.service.bracelet.service.ILumenService;
import com.service.bracelet.util.UtilConsts;

@Service
public class LumenServiceImpl extends ServiceImpl<LumenMapper, Lumen> implements ILumenService {

	@Autowired
	private LumenMapper lumenMapper;

	public void saveList(int userId, Map<String, Object> params) {
		List<Map<String, Object>> list = (List<Map<String, Object>>) MapUtils.getObject(params, UtilConsts.PARAMS_LIST);
		if (CollectionUtils.isEmpty(list)) {
			return;
		}
		Map<Long, Long> queryLumenMap = this.queryLumenMap(userId, list);
		List<Lumen> lumens = new ArrayList<>(list.size());
		for (Map<String, Object> map : list) {
			Lumen lumen = new Lumen();
			Long luTime = MapUtils.getLong(map, UtilConsts.RETURN_LUTIME);
			if (luTime == null) {
				continue;
			}
			Date time = new Date(luTime);
			Long id = queryLumenMap.get(this.getDateFromTime(time));
			if (id != null) {
				lumen.setLuId(id);
			}
			lumen.setLuTime(time);
			lumen.setLuValue(MapUtils.getString(map, UtilConsts.RETURN_LUVALUE));
			lumen.setUserId(userId);
			lumens.add(lumen);
		}
		this.saveOrUpdateBatch(lumens);
	}

	public CommonResult<List<Map<String, Object>>> queryList(Map<String, Object> params) {
		CommonResultPage.setPageParams(params);
		CommonResultPage<List<Lumen>> page = new CommonResultPage(params);
		if (!page.existTotal()) {
			page.setTotal(lumenMapper.queryListTotal(params));
		}
		return page.setData(lumenMapper.queryList(params));
	}

	private Map<Long, Long> queryLumenMap(int userId, List<Map<String, Object>> list) {
		Date min = null;
		for (Map<String, Object> map : list) {
			Date date = new Date(MapUtils.getLong(map, UtilConsts.RETURN_LUTIME));
			if (min == null || date.getTime() < min.getTime()) {
				min = date;
			}
		}
		if (min == null) {
			return Collections.emptyMap();
		}
		min.setDate(min.getDate() - 1);
		Map<String, Object> params = new HashMap<>();
		params.put(UtilConsts.PARAMS_START, 0);
		params.put(UtilConsts.PARAMS_SIZE, 100000);
		params.put(UtilConsts.PARAMS_USERID, userId);
		params.put(UtilConsts.PARAMS_STARTTIME, min);
		List<Map<String, Object>> lumens = this.queryList(params).getData();
		Map<Long, Long> map = new HashMap<>(lumens.size());
		lumens.forEach((lumen) -> {
			Date luTime = (Date) MapUtils.getObject(lumen, UtilConsts.RETURN_LUTIME);
			if (luTime != null) {
				long date = this.getDateFromTime(luTime);
				map.put(date, MapUtils.getLong(lumen, UtilConsts.RETURN_LUID));
			}
		});
		return map;
	}

	private long getDateFromTime(Date time) {
		return new Date(time.getYear(), time.getMonth(), time.getDate(), 0, 0, 0).getTime();
	}

	@Override
	public List<Object[]> queryExportData(Map<String, Object> params) throws IOException {
		List<Map<String, Object>> list = lumenMapper.exportList(params);
		List<Object[]> datas = new ArrayList<>();
		Map<String, Object[]> map = new HashMap<>();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
		for (int i = 0, n = list.size(); i < n; i++) {
			Map<String, Object> data = list.get(i);
			String account = MapUtils.getString(data, "account");
			if (StringUtils.isBlank(account)) {
				continue;
			}
			String userName = MapUtils.getString(data, "userName", "");
			String sex = MapUtils.getString(data, "sex", "");
			Object birthday = MapUtils.getObject(data, "birthday");
			String clazz = MapUtils.getString(data, "clazz", "");
			String school = MapUtils.getString(data, "school", "");
			String luValue = MapUtils.getString(data, "luValue");
			Date luTime = (Date) MapUtils.getObject(data, "luTime");
			if (luValue == null || luTime == null) {
				continue;
			}
			if (StringUtils.isBlank(sex) || StringUtils.equals("0", sex)) {
				sex = "未知";
			} else if (StringUtils.equals("1", sex)) {
				sex = "男";
			} else if (StringUtils.equals("2", sex)) {
				sex = "女";
			}
			String date = sdf.format(luTime);
			String id = account + date;
			Object[] rowData = map.get(id);
			if (rowData == null) {
				String bd = birthday != null && birthday instanceof Date ? sdf.format((Date) birthday) : "";
				rowData = new Object[] { date, account, userName, sex, bd, clazz, school, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
				datas.add(rowData);
				map.put(id, rowData);
			}

			// "无效数据", "小于10", "10-100", "100-500", "500-1000", "1000-3000",
			// "3000-5000","5000-10000","大于10000"
			JsonNode root = new ObjectMapper().readTree(luValue);
			Iterator<JsonNode> eles = root.elements();
			int strColCount = UtilConsts.STR_COLUMN;
			while (eles.hasNext()) {
				JsonNode e = eles.next();
				if (e == null) {
					continue;
				}
				double lu = e.asDouble();
				int index = 0;
				if (lu < 0) {
					index = 0;
				} else if (lu < 10) {
					index = 1;
				} else if (lu >= 10 && lu < 100) {
					index = 2;
				} else if (lu >= 100 && lu < 500) {
					index = 3;
				} else if (lu >= 500 && lu < 1000) {
					index = 4;
				} else if (lu >= 1000 && lu < 3000) {
					index = 5;
				} else if (lu >= 3000 && lu < 5000) {
					index = 6;
				} else if (lu >= 5000 && lu <= 10000) {
					index = 7;
				} else if (lu > 10000) {
					index = 8;
				}
				rowData[index + strColCount] = (int) rowData[index + strColCount] + 1;
			}
		}

		return datas;
	}

	@Override
	public List<Object[]> queryExportDataForAvg(Map<String, Object> params) throws IOException {
		List<Map<String, Object>> list = lumenMapper.exportList(params);
		List<Object[]> datas = new ArrayList<>();
		Map<String, Object[]> map = new HashMap<>();
		Map<String, List<Double>> dataMap = new HashMap<>();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
		for (int i = 0, n = list.size(); i < n; i++) {
			Map<String, Object> data = list.get(i);
			String account = MapUtils.getString(data, "account");
			if (StringUtils.isBlank(account)) {
				continue;
			}
			String userName = MapUtils.getString(data, "userName", "");
			String sex = MapUtils.getString(data, "sex", "");
			Object birthday = MapUtils.getObject(data, "birthday");
			String clazz = MapUtils.getString(data, "clazz", "");
			String school = MapUtils.getString(data, "school", "");
			String luValue = MapUtils.getString(data, "luValue");
			Date luTime = (Date) MapUtils.getObject(data, "luTime");
			if (luValue == null || luTime == null) {
				continue;
			}
			if (StringUtils.isBlank(sex) || StringUtils.equals("0", sex)) {
				sex = "未知";
			} else if (StringUtils.equals("1", sex)) {
				sex = "男";
			} else if (StringUtils.equals("2", sex)) {
				sex = "女";
			}
			String date = sdf.format(luTime);
			String id = account + date;
			Object[] rowData = map.get(id);
			if (rowData == null) {
				String bd = birthday != null && birthday instanceof Date ? sdf.format((Date) birthday) : "";
				rowData = new Object[295];
				rowData[0] = date;
				rowData[1] = account;
				rowData[2] = userName;
				rowData[3] = sex;
				rowData[4] = bd;
				rowData[5] = clazz;
				rowData[6] = school;
				datas.add(rowData);
				List<Double> luData = new ArrayList<Double>(1440);
				luData.addAll(this.getLumenData(luValue));
				map.put(id, rowData);
				dataMap.put(id, luData);
			} else { // 一般是走不到这里的，因为1天就1条数据，1天几条数据的是老的格式，这里稍微兼容下
				List<Double> luData = dataMap.get(id);
				List<Double> cdatas = this.getLumenData(luValue);
				cdatas.forEach(d -> {
					luData.add(0, d);
				});
			}
		}

		// 开始求平均值
		Set<String> keys = map.keySet();
		keys.forEach(k -> {
			Object[] rowData = map.get(k);
			List<Double> luData = dataMap.get(k);
			if (luData != null) {
				int index = 7;
				double sum = 0;
				for (int i = 0, n = luData.size(); i < n; i++) {
					double d = luData.get(i);
					sum += d;
					if ((i + 1) % 5 == 0) {
						rowData[index] = (double) Math.round(sum / 5 * 100) / 100;
						index++;
						sum = 0;
					} else if (i == n - 1) {
						rowData[index] = (double) Math.round(sum / ((i + 1) % 5) * 100) / 100;
					}
				}
			}
		});
		return datas;
	}

	private List<Double> getLumenData(String luValue) throws JsonMappingException, JsonProcessingException {
		JsonNode root = new ObjectMapper().readTree(luValue);
		Iterator<JsonNode> eles = root.elements();
		List<Double> data = new ArrayList<Double>(1440);
		while (eles.hasNext()) {
			JsonNode e = eles.next();
			if (e == null) {
				continue;
			}
			double lu = e.asDouble();
			data.add(lu < 0 ? 0 : lu);
		}
		return data;
	}
}
